package com.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.entity.UserEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ben.huang
 */
@Component
@Slf4j
public class JWTUtil {
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.projectKeyHeader}")
    private String projectKeyHeader;
    @Value("${jwt.appTokenHeader}")
    private String appTokenHeader;
    @Resource
    private HttpServletRequest request;

    /**
     * 生成签名,指定时间后过期,一经生成不可修改，令牌在指定时间内一直有效
     *
     * @return 加密的token
     */
    public String sign(UserEntity user) {
        try {
            long currentTimeMillis = System.currentTimeMillis();
            Date date = new Date(currentTimeMillis + (expiration * 1000));

            Map<String, Object> map = new HashMap<>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            //加密算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            String token = JWT.create()
                    .withHeader(map)//设置头部信息
                    .withAudience("MANAGE")//设置 载荷 签名的观众 也可以理解谁接受签名的
                    //自定义属性
                    .withClaim("data", JSONObject.toJSONString(user))
                    //签发时间
                    .withIssuedAt(new Date(currentTimeMillis))
                    //过期时间
                    .withExpiresAt(date)
                    .sign(algorithm);
            if (StringUtils.hasText(token)) {
                token = tokenHead + " " + token;
            }
            return token;
        } catch (Exception e) {
            return null;
        }
    }

    public String signForever(UserEntity jwtUser) {
        try {
            long currentTimeMillis = System.currentTimeMillis();
            Date date = new Date(currentTimeMillis + (expiration * 1000));

            Map<String, Object> map = new HashMap<>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            //加密算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            String token = JWT.create()
                    .withHeader(map)//设置头部信息
                    .withAudience("MANAGE")//设置 载荷 签名的观众 也可以理解谁接受签名的
                    //自定义属性
                    .withClaim("data", JSONObject.toJSONString(jwtUser))
                    //签发时间
                    .withIssuedAt(new Date(currentTimeMillis))
                    .sign(algorithm);
            if (StringUtils.hasText(token)) {
                token = tokenHead + " " + token;
            }
            return token;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 生成签名,指定时间后过期,一经生成不可修改，令牌在指定时间内一直有效
     *
     * @return 加密的token
     */
    public String signOfTemporary(UserEntity jwtUser, int second) {
        try {
            long currentTimeMillis = System.currentTimeMillis();
            Date date = new Date(currentTimeMillis + (second * 1000));

            Map<String, Object> map = new HashMap<>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            //加密算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            String token = JWT.create()
                    .withHeader(map)//设置头部信息
                    .withAudience("MANAGE")//设置 载荷 签名的观众 也可以理解谁接受签名的
                    //自定义属性
                    .withClaim("data", JSONObject.toJSONString(jwtUser))
                    //签发时间
                    .withIssuedAt(new Date(currentTimeMillis))
                    //过期时间
                    .withExpiresAt(date)
                    .sign(algorithm);
            if (StringUtils.hasText(token)) {
                token = tokenHead + " " + token;
            }
            return token;
        } catch (Exception e) {
            return null;
        }
    }



    public String getToken() {
        return request.getHeader(tokenHeader);
    }



    public boolean isTokenExpired(String token) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier verifier = JWT.require(algorithm)
                .withAudience("MANAGE")
                .build();
        try {
            DecodedJWT verify = verifier.verify(token);
            Date expiredDate = verify.getExpiresAt();
            return expiredDate.before(new Date());
        } catch (TokenExpiredException ex) {
            log.error(ex.getMessage());
            return true;
        } catch (JWTVerificationException ex) {
            log.error(ex.getMessage());
        }
        return false;
    }

}
